package fr.vvins.core.search.query;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;

import org.apache.commons.lang.StringUtils;


/**
 * Bean container for search query.
 * @author fguay
 *
 */
public class SearchQuery implements Cloneable {
    
    public static enum ORDER{desc, asc;};
     
    private SortedMap<String, SearchQuery.ORDER> sortParams;

    private String query;
    
    private List<String> filterQuery;
    
    private boolean facet;
    
    private List<String> facetFields;
    
    private List<String> facetLimit;
    
    private Map<String,Map<String,Long>> rangeLimit;
    
    private String facetQuery;
    
    private int max;
    
    private int start;
    
    
    /**
    * Build a query with default solr config.
    * @param pQuery
    */
   public SearchQuery(){
       setStart(-1);
       setMax(-1);
       setFacet(false);
       setRangeLimit(new HashMap<String,Map<String,Long>>());
       setFacetFields(new ArrayList<String>());
   }
    
    /**
     * Build a query with default solr config.
     * @param pQuery
     */
    public SearchQuery(String pQuery){
        setQuery(pQuery);
        setStart(-1);
        setMax(-1);
        setFacet(false);
        List<String> facetFields = new ArrayList<String>();
        setFacetFields(facetFields);
        
    }
    
    /**
     * Build a query with dedicated start and max for pagination.
     * @param pQuery
     * @param pStart
     * @param pMax
     */
    public SearchQuery(String pQuery, int pStart, int pMax ){
        setQuery(pQuery);
        setStart(pStart);
        setMax(pMax);
        setFacet(false);
        List<String> facetFields = new ArrayList<String>();
        setFacetFields(facetFields);
    }
    
    /**
     * Build a query with dedicated start and max for pagination
     * and add sort information.
     * @param pQuery
     * @param pStart
     * @param pMax
     * @param pSortParams
     */
    public SearchQuery(String pQuery, int pStart, int pMax, SortedMap<String, SearchQuery.ORDER> pSortParams){
        setQuery(pQuery);
        setStart(pStart);
        setMax(pMax);
        setSortParams(pSortParams);
        setFacet(false);
        List<String> facetFields = new ArrayList<String>();
        setFacetFields(facetFields);
    }
    
    /**
     * Build a query with dedicated start and max for pagination
     * and add sort information.
     * @param pQuery
     * @param pStart
     * @param pMax
     * @param pSortParams
     */
    public SearchQuery(String pQuery, int pStart, int pMax, boolean facet, SortedMap<String, SearchQuery.ORDER> pSortParams){
        setQuery(pQuery);
        setStart(pStart);
        setMax(pMax);
        setSortParams(pSortParams);
        setFacet(facet);
        List<String> facetFields = new ArrayList<String>();
        setFacetFields(facetFields);
    }
    
    public void addFilterQuery(String pFilterQuery){
    	if(!StringUtils.isEmpty(pFilterQuery)){
	    	if(filterQuery == null){
	    		filterQuery = new ArrayList<String>();
	    	}
	    	filterQuery.add(pFilterQuery);
    	}
    }
    
    public void addRangeFilter(String pFilter, Long start, Long end, Long gap){
    	Map<String,Long> filterValue = new HashMap<String,Long>();
    	filterValue.put("start", start);
    	filterValue.put("end", end);
    	filterValue.put("gap", gap);
    	getRangeLimit().put(pFilter, filterValue);
    }

    public SortedMap<String, SearchQuery.ORDER> getSortParams() {
        return sortParams;
    }

    public void setSortParams(SortedMap<String, SearchQuery.ORDER> pSortParams) {
        sortParams = pSortParams;
    }

    public String getQuery() {
        return query;
    }

    public void setQuery(String pQuery) {
        query = pQuery;
    }

    public int getMax() {
        return max;
    }

    public void setMax(int pMax) {
        max = pMax;
    }

    public int getStart() {
        return start;
    }

    public void setStart(int pStart) {
        start = pStart;
    }

	public List<String> getFilterQuery() {
		return filterQuery;
	}

	public void setFilterQuery(List<String> filterQuery) {
		this.filterQuery = filterQuery;
	}
	
	public boolean getFacet() {
		return facet;
	}

	public void setFacet(boolean facet) {
		this.facet = facet;
	}

	public List<String> getFacetFields() {
		return facetFields;
	}

	public void setFacetFields(List<String> facetFields) {
		this.facetFields = facetFields;
	}

	
	@Override
	public Object clone() {
    	SearchQuery query = new SearchQuery();
    	query.setFacet(new Boolean(getFacet()));
		query.setMax(new Integer(getMax()));
		query.setStart(new Integer(getStart()));
		query.setQuery(new String(getQuery()));
		query.setSortParams(getSortParams());
		
		List<String> nFilter = new ArrayList<String>();
		List<String> nField = new ArrayList<String>();
		
		nFilter.addAll(getFilterQuery());
		nField.addAll(getFacetFields());
		query.setFilterQuery(nFilter);
		query.setFacetFields(nField);
		return query;
    }

	public String getFacetQuery() {
		return facetQuery;
	}

	public void setFacetQuery(String facetQuery) {
		this.facetQuery = facetQuery;
	}

	public List<String> getFacetLimit() {
		return facetLimit;
	}

	public void setFacetLimit(List<String> facetLimit) {
		this.facetLimit = facetLimit;
	}

	@Override
	public String toString() {
		return "SearchQuery [sortParams=" + sortParams + ", query=" + query
				+ ", filterQuery=" + filterQuery + ", facet=" + facet
				+ ", facetFields=" + facetFields + ", facetLimit=" + facetLimit
				+ ", facetQuery=" + facetQuery + ", max=" + max + ", start="
				+ start + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (facet ? 1231 : 1237);
		result = prime * result
				+ ((facetFields == null) ? 0 : facetFields.hashCode());
		result = prime * result
				+ ((facetLimit == null) ? 0 : facetLimit.hashCode());
		result = prime * result
				+ ((facetQuery == null) ? 0 : facetQuery.hashCode());
		result = prime * result
				+ ((filterQuery == null) ? 0 : filterQuery.hashCode());
		result = prime * result + max;
		result = prime * result + ((query == null) ? 0 : query.hashCode());
		result = prime * result
				+ ((sortParams == null) ? 0 : sortParams.hashCode());
		result = prime * result + start;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		SearchQuery other = (SearchQuery) obj;
		if (facet != other.facet)
			return false;
		if (facetFields == null) {
			if (other.facetFields != null)
				return false;
		} else if (!facetFields.equals(other.facetFields))
			return false;
		if (facetLimit == null) {
			if (other.facetLimit != null)
				return false;
		} else if (!facetLimit.equals(other.facetLimit))
			return false;
		if (facetQuery == null) {
			if (other.facetQuery != null)
				return false;
		} else if (!facetQuery.equals(other.facetQuery))
			return false;
		if (filterQuery == null) {
			if (other.filterQuery != null)
				return false;
		} else if (!filterQuery.equals(other.filterQuery))
			return false;
		if (max != other.max)
			return false;
		if (query == null) {
			if (other.query != null)
				return false;
		} else if (!query.equals(other.query))
			return false;
		if (sortParams == null) {
			if (other.sortParams != null)
				return false;
		} else if (!sortParams.equals(other.sortParams))
			return false;
		if (start != other.start)
			return false;
		return true;
	}

	public Map<String, Map<String, Long>> getRangeLimit() {
		return rangeLimit;
	}

	public void setRangeLimit(Map<String, Map<String, Long>> rangeLimit) {
		this.rangeLimit = rangeLimit;
	}
    
}
